import java.io.IOException;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;


public class NioClient {
	private String host;
	private int port;
	private SocketChannel sc;
	private Selector sel;
	private String name;
	private CharsetEncoder encoder = Charset.forName("utf-8").newEncoder();
	private CharsetDecoder decoder = Charset.forName("utf-8").newDecoder();
	private ByteBuffer buffer = ByteBuffer.allocate(1024);
	private ArrayBlockingQueue<String> msgbuffer = new ArrayBlockingQueue<String>(10);
	private String seperator = System.getProperty("line.separator");
	private SelectionKey key;
	public NioClient(String host,int port,String name){
		this.host = host;
		this.port = port;
		this.name = name;
		try {
			sc = SocketChannel.open();
			sc.configureBlocking(false);  //设置异步方式 
			sel = Selector.open();   //创建选择器
			this.key = sc.register(sel, SelectionKey.OP_CONNECT);
			sc.connect(new InetSocketAddress(host,port)); //发起连接
			//创建线程发送消息
			inputHandle();
			//start();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void inputHandle(){
		new Thread(new Runnable(){

			@Override
			public void run() {
				Scanner scanner = new Scanner(System.in).useDelimiter(seperator);
				while(true){
					String msg = scanner.next();
					inputMsg(msg);
				}
			}
			
		}).start();
	}
	
	
	public void inputMsg(String msg){
		if(msg.length() > 0){
			msgbuffer.offer(msg);
			try{
				if(((SocketChannel)(this.key.channel())).isConnected()){
					this.key.interestOps(SelectionKey.OP_WRITE);
					sel.wakeup();
				}
			}catch(Exception e){
				System.out.println("error"+e.getMessage());
				return;
			}
		}
	}
	
	public void start(){
		while(true){
			try {
				//if(sel.selectNow() == 0 )continue;
				sel.select();
				Iterator itr = sel.selectedKeys().iterator();
				while(itr.hasNext()){
					SelectionKey key = (SelectionKey) itr.next();
					itr.remove();
					if(key.isConnectable()){  //连接已建立
						while(sc.isConnectionPending()){
							sc.finishConnect();
						}
						sc.write(encoder.encode(CharBuffer.wrap("Welcome "+name+", time:"+new java.util.Date()+seperator)));
						this.key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
					}
					
					if(key.isReadable()){
						int count = 0;
						while((count = sc.read(buffer)) > 0){
							buffer.flip();
							CharBuffer cb = decoder.decode(buffer);
							System.out.print(cb.toString());
							buffer.clear();
						}
						//System.out.println();
					}
					
					if(key.isWritable()){
						String msg = null;
						while((msg = msgbuffer.poll()) != null){
							sc.write(encoder.encode(CharBuffer.wrap(name+": "+msg+seperator)));
						}
						this.key.interestOps(SelectionKey.OP_READ);  //无数据发送只关心读
					}
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return;
			}
			
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		if(args.length < 2){
			System.out.println("please input host and port. example:java client 127.0.0.1 8080");
			return;
		}
		final String host = args[0];
		final String port = args[1];
		System.out.println("input your name");
		Scanner scanner = new Scanner(System.in);
		String name = scanner.next();
		new NioClient(host,Integer.parseInt(port),name).start();
		
		/*final Random r = new Random();
		//测试100个客户端
		for(int i=0;i<100;i++){
			new Thread(new Runnable(){

				@Override
				public void run() {
					// TODO Auto-generated method stub
					NioClient nc = new NioClient(host,Integer.parseInt(port),""+r.nextLong());;
					new Thread(new test(nc)).start();
					
					nc.start();
				}
				
			}).start();
			
		}*/
	}

}

class test implements Runnable{
	private NioClient nc = null;
	Random r = new Random();
	public test(NioClient nc){
		this.nc = nc;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		// TODO Auto-generated method stub
		while(true){
			try {
				Thread.sleep(1000);
				if(nc != null)
					nc.inputMsg("aaaa"+r.nextFloat());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	
}
